#include <cassert>
#include <sstream>
#include <map>

#include "util.h"
#include "sent.h"

extern map <string,int> dict,gaz;

extern int EXTRACTOR;

structure sent::giveStructure() const {
   structure r(ent.size());

   for (int i=0; i<ent.size(); ++i) {
      r.putBottomLabel(i,ent[i].et,ent[i].es,ent[i].ee);
   }

   if (EXTRACTOR != ENTITY_ONLY) {
   for (int i=0; i<rel.size(); ++i) {
      int e1, e2;
      for (int j=0; j<ent.size(); ++j) {
	 if (ent[j].eid==rel[i].reid1) {
	    e1=j;
	    break;
	 }
      }
      for (int j=0; j<ent.size(); ++j) {
	 if (ent[j].eid==rel[i].reid2) {
	    e2=j;
	    break;
	 }
      }
      r.putInternalLabel(e1,e2,rel[i].rtype,ent[e1].et,ent[e2].et);
   }
   }
   r.fillIn();
   return r;
}


void sent::giveEntities(vector <string> &et, vector <int> &st, vector <int> &en) const {
   for (int i=0; i<ent.size(); ++i) {
      et.push_back(ent[i].et);
      st.push_back(ent[i].es);
      en.push_back(ent[i].ee);
   }
}
void sent::giveCandidateEntities(vector <int> &st, vector <int> &en) const {
   for (int i=0; i<ent.size(); ++i) {
      st.push_back(ent[i].es);
      en.push_back(ent[i].ee);
   }
}


bool sent::read(ifstream &in, bool onlyAdjacent) {
   string s;
   while (s != "<sent>" && in) in>>s;
   if (!in) return false;

   in>>s;
   while (s != "</sent>" && in) {
      int i;
      if (s == "<word>") {
	 in>>i;
	 ind = i;
	 in>>s;
	 assert(s=="Other" || s=="O" || s=="Org" || s=="Peop" || s=="Loc");
	 etype.push_back(s);
	 in>>i;
	 in>>s;
	 in>>s;
	 pos.push_back(s);
	 in>>s;
	 word.push_back(s);
	 in>>s>>s>>s;
	 in>>s;
	 assert(s=="</word>");
      }
      
      //if (EXTRACTOR != ENTITY_ONLY && s=="<rel>") {
      if (s=="<rel>") {
	 in>>i;
	 rs.push_back(i);
	 in>>i;
	 re.push_back(i);
	 in>>s;
	 assert(s=="Live_In"||s=="Located_In"||s=="OrgBased_In"||s=="Work_For"||s=="Kill");
	 rtype.push_back(s);
	 in>>s;
	 assert(s=="</rel>");
      }
      in>>s;
   }
   if (in) {
      change(onlyAdjacent);

      for (int i=0; i<nword.size(); ++i) {
	 inword.push_back(mapInsert(nword[i]));
      }
      for (int i=0; i<npos.size(); ++i) {
	 inpos.push_back(mapInsert(npos[i]));
      }

      return true;
   }
   else return false;
}

int relTotal=0;
int ccTotal=0;
/*
void sent::countCrissCrosses() const {
   int cc=0;
   for (int i=0; i<rel.size(); ++i) {
      for (int j=i+1; j<rel.size(); ++j) {
	 int c=0;
	 if ((rel[j].reid1 > rel[i].reid1 && rel[j].reid1 < rel[i].reid2)||
	       (rel[j].reid1 < rel[i].reid1 && rel[j].reid1 > rel[i].reid2)) {
	    if ((rel[j].reid2 > rel[i].reid1 && rel[j].reid2 > rel[i].reid2)||
		  (rel[j].reid2 < rel[i].reid1 && rel[j].reid2 < rel[i].reid2)) ++c;
	 }
	 if ((rel[j].reid2 > rel[i].reid1 && rel[j].reid2 < rel[i].reid2)||
	       (rel[j].reid2 < rel[i].reid1 && rel[j].reid2 > rel[i].reid2)) {
	    if ((rel[j].reid1 > rel[i].reid1 && rel[j].reid1 > rel[i].reid2)||
		  (rel[j].reid1 < rel[i].reid1 && rel[j].reid1 < rel[i].reid2)) ++c;
	 }
         if (c > 0) {
	    ++cc;
	    write(cout);
         }
      }
   }
   relTotal += rel.size();
   ccTotal += cc;
   cout<<ccTotal<<" "<<relTotal<<"\n";
}*/


void sent::change(bool onlyAdjacent) {
   static int EID=0;

   vector <string> et, eid;
   vector <int> ee, es, iid;
   vector <string> reid1, reid2;

   reid1.resize(rs.size());
   reid2.resize(re.size());
   for (int i=0; i<word.size(); ++i) {
      vector <string> wst,pst;
      split(word[i],wst);
      split(pos[i],pst);
      if (wst.size() != pst.size()) { // clusters the front => N/N => [a/b]/[c]
	 assert(wst.size() > pst.size());
	 while (wst.size() != pst.size()) {
	    assert(wst.size()>1);
	    wst[0] = wst[0]+wst[1];
	    wst.erase(wst.begin()+1);
	 }
      }
      assert(wst.size()==pst.size());
      int s=nword.size();
      for (int j=0; j<wst.size(); ++j) {
	 nword.push_back(wst[j]);
	 npos.push_back(pst[j]);
      }
      if (etype[i] != "O") {
	 es.push_back(s);
	 ee.push_back(nword.size()-1);
	 et.push_back(etype[i]);
	 iid.push_back(EID);
	 string id = "ID_" + itos(EID++);
	 eid.push_back(id);
	 for (int j=0; j<rs.size(); ++j) {
	    if (rs[j]==i) reid1[j]=id;
	 }
	 for (int j=0; j<re.size(); ++j) {
	    if (re[j]==i) reid2[j]=id;
	 }
      }
   }

   for (int i=0; i<eid.size(); ++i) {
      entity e;
      e.eid = eid[i];
      e.id = iid[i];
      e.et = et[i];
      e.es = es[i];
      e.ee = ee[i];
      ent.push_back(e);
   }
   sort(ent.begin(), ent.end());

   for (int i=0; i<rtype.size(); ++i) {
      relation r;
      r.rtype = rtype[i];
      r.reid1 = reid1[i];
      r.reid2 = reid2[i];

      int e1, e2;
      for (int j=0; j<ent.size(); ++j) {
	 if (ent[j].eid==r.reid1) {
	    e1=j;
	    break;
	 }
      }
      for (int j=0; j<ent.size(); ++j) {
	 if (ent[j].eid==r.reid2) {
	    e2=j;
	    break;
	 }
      }
      if (onlyAdjacent) {
         //if (e1-e2 > 1 || e2-e1 > 1) continue; // ignore if not adjacent
      }
      rel.push_back(r);
   }
}

void sent::split(const string &s, vector <string> &st) const {
   // splits the string s by '/' character
   st.clear();
   string n;
   for (int i=0; i<s.size(); ++i) {
      if (s[i]=='/') {
	 st.push_back(n);
	 n="";
      }
      else n.push_back(s[i]);
   }
   st.push_back(n);
}

ostream& sent::write(ostream& out) const {
   out<<"<sent>\n";
   cout<<"<words> ";
   for (int i=0; i<nword.size(); ++i) {
      out<<i<<" "<<nword[i]<<" "<<npos[i]<<"   ";
   }
   cout<<"</words>\n";
   //for (int i=0; i<word.size(); ++i) {
     // out<<"<word>\n";
     // out<<ind<<" "<<etype[i]<<" "<<i<<" O "<<pos[i]<<" "<<word[i]<<" O O O\n";
     // out<<"</word>\n";
  // }
   for (int i=0; i<ent.size(); ++i) {
      out<<"<entity> "<<ent[i].eid<<" "<<ent[i].et<<" "<<ent[i].es<<" "<<ent[i].ee<<" </entity>\n";
   }
   for (int i=0; i<rel.size(); ++i) {
      out<<"<rel>\n";
      out<<rel[i].rtype<<" "<<rel[i].reid1<<" "<<rel[i].reid2<<"\n";
      out<<"</rel>\n";
   }
   out<<"</sent>\n";

   //cout<<nword.size()<<"\n";
   //for (int i=0; i<nword.size(); ++i) {
     // out<<i<<" "<<nword[i]<<" "<<npos[i]<<"   ";
   //}
   //out<<"\n";

   //for (int i=0; i<eid.size(); ++i) {
     // out<<"Entity: "<<eid[i]<<" "<<et[i]<<" "<<es[i]<<" "<<ee[i]<<"\n";
   //}
   //for (int i=0; i<rtype.size(); ++i) {
     // out<<"Relation: "<<rtype[i]<<" "<<reid1[i]<<" "<<reid2[i]<<"\n";
   //}
   return out;
}

string sent::ascii(const string &s) const {
   string r;
   for (int i=0; i<s.size(); ++i) {
      if ((s[i] >= 'a' && s[i] <= 'z') || (s[i] >= 'A' && s[i] <= 'Z') || (s[i]=='_')) {
	 r.push_back(s[i]);
      }
      else {
	 r += "_ASCII";
	 r += itos((int) s[i]);
	 r += "_";
      }
   }
   return r;
}

string sent::gFeature(const string &s) const {
   string r;
   bool a=false, A=false, zero=false;
   for (int i=0; i<s.size(); ++i) {
      if (s[i] >= 'a' && s[i] <= 'z') {
	 if (! a) {
	    r.push_back('a');
	    a=true;
	 }
      }
      else a=false;
      if (s[i] >= 'A' && s[i] <= 'Z') {
	 if (! A) {
	    r.push_back('A');
	    A=true;
	 }
      }
      else A=false;
      if (s[i] >= '0' && s[i] <= '9') {
	 if (! zero) {
	    r.push_back('0');
	    zero=true;
	 }
      }
      else zero=false;

      if (!a && !A && !zero) {
	 r += "_ASCII";
	 r += itos((int) s[i]);
	 r += "_";
      }

   }
   return r;
}

void sent::writeSent(ostream &out) const {
   /*
   for (int i=0; i<nword.size(); ++i) out<<nword[i]<<" ";
   out<<"\n";
   */
}
